package cn.dakaqi.open.auth;

import cn.dakaqi.annotation.EncryptionParam;
import cn.dakaqi.entities.Customer;
import cn.dakaqi.exception.EncryptionException;
import cn.dakaqi.exception.LoginRequiredException;
import cn.dakaqi.exception.MaibaoParamException;
import cn.dakaqi.open.util.BodyReaderHttpServletRequestWrapper;
import cn.dakaqi.services.CustomerService;
import cn.dakaqi.utils.encryption.MapUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.google.gson.Gson;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Map;

@Component
public class EncryptionInterceptor extends HandlerInterceptorAdapter {

    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
    private static final Gson gson = new Gson();

    @Resource
    private CustomerService customerService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            EncryptionParam param = handlerMethod.getMethodAnnotation(EncryptionParam.class);
            if (null == param) {
                return true;
            }
            ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
            String paramJsonString = parseRequestBody(requestWrapper);
            System.out.println("第一步---1---"+paramJsonString);

            if(StringUtils.isEmpty(paramJsonString)){
                throw new EncryptionException("", "param is null");
            }

            JSONObject jsonObject = JSONObject.parseObject(paramJsonString);

            String customerCode = jsonObject.getString("customerCode");
            String sign = jsonObject.getString("sign");
            String nonce = jsonObject.getString("nonce");
            request.getSession().setAttribute("jsonParam", paramJsonString);
            System.out.println("第二步---2---"+request.getSession().getAttribute("jsonParam").toString());

            if (StringUtils.isEmpty(sign) || StringUtils.isEmpty(nonce) || StringUtils.isEmpty(customerCode)) {
                throw new EncryptionException("", "param Error");
            } else {
                Customer customer = customerService.findByCode(customerCode);
                if (customer == null) {
                    return false;
                }
                Map<String, String> map = JSON.parseObject(paramJsonString, new TypeReference<Map<String, String>>() {
                });
                map = MapUtil.order(map);
                if (map.containsKey("sign")) {
                    map.remove("sign");
                }
                String paramMap = MapUtil.mapJoin(map, false, false);
                paramMap = paramMap + "&key=" + customer.getSecretKey();
                String pass = DigestUtils.md5Hex(paramMap).toUpperCase();

                if (!pass.equalsIgnoreCase(jsonObject.getString("sign"))) {
                    throw  new MaibaoParamException("1","加密参数sign失效！");
                }
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//        preHandle(request, response, handler);
    }

    private String getRequestBodyJson(InputStream inputStream) throws IOException {
        Reader input = new InputStreamReader(inputStream, "UTF-8");
        Writer output = new StringWriter();
        char[] buffer = new char[DEFAULT_BUFFER_SIZE];
        int n;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
        return output.toString();
    }

    @SuppressWarnings("unused")
    public <T> T parseRequestBody(Class<T> type, ServletRequest request) throws IOException {
        InputStream inputStream = request.getInputStream();
        String json = getRequestBodyJson(inputStream);
        return gson.fromJson(json, type);
    }

    public String parseRequestBody(ServletRequest request) throws IOException {
        InputStream inputStream = request.getInputStream();
        return getRequestBodyJson(inputStream);
    }
}